import java.util.Arrays;
import java.util.Calendar;
import java.util.TimeZone;
/**
 * This class is instantiated to represent an Event object.  It uses Calendar Objects to represent start and end times.
 * It uses String Objects to hold other data associated with Event and contains getter and setter methods for them.
 * Methods prefixed with "ics" are specially formatted to output Strings to be interpreted as an iCal .ics file.
 * @author Team Boyton(Rhys Higa, Justin Shoemaker Jeffrey Tamashiro) - ICS 314 - Final Project - 8/12/13
 */
public class Event {
	private String name;
	private Calendar timeNow;
	private Calendar start;
	private Calendar end;
	private String timeZone;	
	private String classification;
	private String comment;
	private String location;
	private String resources;
	private boolean recur;
	private boolean[] recurring;
	
	/**
	* Constructor Method sets up three Calendar Objects identically at the current date-time with no leniency.
	* It also initializes all Strings to empty and defaults the repeat option to false.
	*/
	public Event() {
		timeZone = "+00";
		timeNow = Calendar.getInstance();
		timeNow.setLenient(false);
		start = (Calendar)timeNow.clone();
		end = (Calendar)timeNow.clone();
		classification = "";
		comment = "";
		location = "";
		resources = "";
		recur = false;
	}
	
// Setter Methods	
	
	/**
	* This method uses input to set time zones for start and end Date-Times.
	* @param String representing Time Zone formatted to set TimeZone as custom designated as
	* plus or minus GMT.
	*/
	public void setTimeZone(String timeZone){
		this.timeZone = timeZone;
		start.setTimeZone(TimeZone.getTimeZone("GMT" + timeZone));
		end.setTimeZone(TimeZone.getTimeZone("GMT" + timeZone));
	}
	/**
	 * This method takes five int parameters to set the Calendar for the start date-time for the Event.
	 * The get method is called to ensure an exception is thrown when invalid date is set.
	 * @param year int representing the year
	 * @param month int representing the month (1 - 12)
	 * @param date int representing the day of the month (date)
	 * @param hour int representing the hour (00 - 23)
	 * @param min int representing the minute (00 - 59)
	 * @throws IllegalArgumentException observed when user inputs an invalid date (ex. February 31st)
	 */
	public void setStart(int year, int month, int date, int hour, int min) throws IllegalArgumentException{
		start.set(year, month - 1, date, hour, min);
		start.get(Calendar.DAY_OF_WEEK);
	}
	/**
	 * This method takes five int parameters to set the Calendar for the end date-time for the Event.
	 * The get method is called to ensure an exception is thrown when invalid date is set.
	 * @param year int representing the year
	 * @param month int representing the month (1 - 12)
	 * @param date int representing the day of the month (date)
	 * @param hour int representing the hour (00 - 23)
	 * @param min int representing the minute (00 - 59)
	 * @throws IllegalArgumentException observed when user inputs an invalid date (ex. February 31st)
	 */
	public void setEnd(int year, int month, int date, int hour, int minute) throws IllegalArgumentException{
		end.set(year, month - 1, date, hour, minute);
		end.get(Calendar.DAY_OF_WEEK);
	}
	
	/**
	 * Sets name to be used in output filename
	 * @param name String from GUI input
	 */
	public void setName(String name){
		this.name = name;
	}
	/**
	 * Sets classification to be used in ics output file
	 * @param classification String from GUI input
	 */
	public void setClassification(String classification){
		this.classification = classification;
	}
	/**
	 * Sets comment to be used in ics output file
	 * @param comment String from GUI input
	 */
	public void setComment(String comment){
		this.comment = comment;
	}
	/**
	 * Sets location to be used in ics output file
	 * @param location String from GUI input
	 */
	public void setLocation(String location){
		this.location = location;
	}
	/**
	 * Sets resources to be used in ics output file
	 * @param resources String from GUI input
	 */
	public void setResources(String resources){
		this.resources = resources;
	}
	/**
	 * Sets values telling the program if an event will repeat and if so on which days of the week it will repeat.
	 * @param repeat boolean true if repeating will occur, false if not
	 * @param repeatDays boolean array of size 7, true for days of the week event will occur
	 */
	public void setRecurring(boolean repeat, boolean[] repeatDays){
		this.recur = repeat;
		this.recurring = Arrays.copyOf(repeatDays, 7);
	}

// Getter Methods
	/**
	 * Getter method for name variable
	 * @return String name
	 */
	public String getName(){
		return name;
	}
	/**
	 * Getter method for classification variable
	 * @return String classification
	 */
	public String getClassification(){
		return classification;
	}
	/**
	 * Getter method for comment variable
	 * @return String comment
	 */
	public String getComment(){
		return comment;
	}
	/**
	 * Getter method for location variable
	 * @return String location
	 */
	public String getLocation(){
		return location;
	}
	/**
	 * Getter method for resources variable
	 * @return String resources
	 */
	public String getResources(){
		return resources;
	}
	/**
	 * Getter method for String representation of timezone
	 * @return String based on timezone of Calendar Object
	 */
	public String getTimeZone(){
		return start.getTimeZone().getDisplayName();
	}
	/**
	 * Method for String representation of start date-time for gui
	 * @return String based on start Calendar Object
	 */
	public String guiStart(){
		return guiDate(start);
	}
	/**
	 * Method for String representation of end date-time for gui
	 * @return String based on end Calendar Object
	 */
	public String guiEnd(){
		return guiDate(end);
	}
	/**
	 * Helper method that takes a Calendar Object and formats an output String suitable for the GUI
	 * @param cal Calendar Object to pull date-time from
	 * @return String representation for use in GUI
	 */
	private String guiDate(Calendar cal){
		return String.format("%1$tb %1$te, %1$tY %1$tH:%1$tM %1$tZ", cal);
	}
	/**
	 * Method that creates a String to show weekly recursion based on boolean array 
	 * @return String representation of recursion for use in GUI
	 */
	public String guiRecurring(){
		String [] weekDays = {"Su ","Mo ","Tu ","We ","Th ","Fr ","Sa "};
		String result = "";
		if(recur){
			for(int i = 0; i < 7; i ++){
				if(recurring[i]){
					result = result + weekDays[i];
				}
			}
		}
		return result;
	}
	/**
	 * Method that creates a String for creation of .ics file
	 * @return String representation of timeNow
	 */
	public String icsNow(){
		return icsDate(timeNow);
	}
	/**
	 * Method that creates a String for creation of .ics file
	 * @return String representation of start
	 */
	public String icsStart(){
		return icsDate(start);
	}
	/**
	 * Method that creates a String for creation of .ics file
	 * @return String representation of end
	 */
	public String icsEnd(){
		return icsDate(end);
	}
	/**
	 * Helper method that creates a String readable according to RFC 5455 specifications
	 * @return String representation of a date-time
	 */
	private String icsDate(Calendar input){
		Calendar cal = (Calendar)input.clone();
		cal.add(Calendar.MILLISECOND, (-1) * cal.getTimeZone().getRawOffset());
		return String.format("%1$tY%1$tm%1$tdT%1$tH%1$tM00Z", cal);
	}
	/**
	 * Method that creates a String for creation of .ics file
	 * @return String representation of time zone offset
	 */
	public String icsOffset(){
		return timeZone + "00";
	}
	/**
	 * Method that creates a String for creation of .ics file
	 * @return String representation of weekly recursion
	 */	
	public String icsRecurring(){
		String[] days = {"SU","MO","TU","WE","TH","FR","SA"};
		String result = "";
		
		if(recur){
			result = result + "RRULE:FREQ=WEEKLY;BYDAY=";
			for(int i = 0; i < 7; i++){
				if(recurring[i]){
					result = result + days[i] + ",";
				}
			}
			result = result.substring(0,result.length() - 1);
		}
		return result;
	}
	/**
	 * Predicate method that determines if an end date-time is before a start date-time
	 * @return boolean is true if start is on or preceeding end, false if not
	 */
	public boolean valiDate(){
		if(start.compareTo(end) <= 0){
			return true;
		}
		else{
			return false;
		}
	}
	/**
	 * Method clears String fields to default when reset button is pressed
	 */
	public void reset(){
		comment = "";
		location = "";
		resources = "";
		recur = false;
	}
	/**
	 * Method mainly used for testing, gives a String output summary of Event Object variables
	 */
	public String toString(){
		
		String result = "";
		
		result = result + "\nTime Zone: " + getTimeZone();
		result = result + "\nStart Time: " + guiStart();
		result = result + "\nEnd Time: " + guiEnd();
		result = result + "\nClassification: " + getClassification();
		result = result + "\nComment: " + getComment();
		result = result + "\nLocation: " + getLocation();
		result = result + "\nResources: " + getResources();
		result = result + "\nICS Start: " + icsStart();
		result = result + "\nICS End:   " + icsEnd();
		result = result + "\nICS Recur: " + icsRecurring();
		
		return result;
	}
}